package com.hfzy.ihk.web.aliyuncall.support.cloudcall.base;

import com.alibaba.fastjson.JSONObject;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.facade.aliyuncall.CallRecordBaseEntity;
import com.hfzy.ihk.facade.aliyuncall.vo.CallHistory;
import com.hfzy.ihk.web.aliyuncall.constant.Constants;
import com.hfzy.ihk.web.aliyuncall.constant.RedisFields;
import com.hfzy.ihk.web.aliyuncall.constant.UserMsgType;
import com.hfzy.ihk.web.aliyuncall.support.disruptor.base.DisruptorEvent;
import com.hfzy.ihk.web.aliyuncall.support.disruptor.base.DisruptorHandlerAdapter;
import com.hfzy.ihk.web.aliyuncall.vo.AliyunCallState;
import com.lmax.disruptor.RingBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;

import java.util.Map;

/**
 * Created by Administrator on 2016/5/26.
 * @author wws
 * 处理呼叫状态业务逻辑抽象类
 * 流程：
 * 1、跟进sessionId从redis读取callHistory
 * 2、如果存在，更新callHistory状态（判断状态逻辑），状态发送到websocketServer
 * 3、更新redis
 * 4.推送的ES服务入库
 */
public abstract class AbstractCallStateHandler<T extends CallRecordBaseEntity,E extends DisruptorEvent<T>> implements DisruptorHandlerAdapter<E> {

    private static final Logger logger = LoggerFactory.getLogger(AbstractCallStateHandler.class);




    /**
     * 指定一个缓存CallHistory数据的Map
     * */
    protected abstract Map<String,CallHistory> getMemoryCache();

    /**
     * EventHandler
     */
    @Override
    public void onEvent(E event, long sequence, boolean endOfBatch) throws Exception {

        try {
            Long old = System.currentTimeMillis();

           // procces(event.getData());

            old = System.currentTimeMillis()-old;
            logger.debug("eventHandler handle use time:{}",old);
        } catch (Exception e) {
            logger.error("AbstactCallStateHandler exception",e);
        }

    }

    /**
     * workHandler
     */
    @Override
    public void onEvent(E event) throws Exception {

        try {
            Long old = System.currentTimeMillis();

            procces(event.getData());

            old = System.currentTimeMillis()-old;
            logger.debug("workHandler handle use time:{}",old);
        } catch (Exception e) {
            logger.error("AbstactCallStateHandler exception",e);
        }

    }

    /**
     * 流程方法
     * 1、跟进sessionId从redis读取callHistory
     * 2、如果存在，更新callHistory状态（判断状态逻辑），状态发送到websocketServer
     * 3、更新redis
     * 4、进入批量插入队列
     *
     * @param state*/
    protected void procces(T state){

        Map<String,String> callHistoryMap = null;
        /*读不到，就不管了，不能影响状态返回*/

        try {
            callHistoryMap = readRedis(state.getSessionId());
        } catch (Exception e) {
            logger.error("{} readRedis Failed! sessionId:{}",state.getSessionId());
            handleReadRedisFailed(state);
        }

        Map<String,Map<String,String>> resultMap = null;

        try {
            //分析状态
            resultMap = analyzeCallState(state,callHistoryMap);

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("{} analyzeCallState Failed!sessionId:{}",state.getSessionId());
        }

        try {
            //将状态推送到客户端
            pushStateToClient(callHistoryMap,resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("{} pushStateToClient Failed!sessionId:{}",state.getSessionId());
            //推送失败处理
            handlePushStateToClientFail();
        }

        try {
            /*写入呼叫状态*/
            writeRedis(state.getSessionId(),resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS));
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("{} writeRedis Failed! sessionId:{}",state.getSessionId());
            handleWriteRedisFailed(state.getSessionId(),resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS));
        }

        boolean check = false;

        try {
            logger.debug("{} resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS):{}", JSONObject.toJSONString(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS)));
            if(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS).isEmpty())
                return;
            //合并一下map（redis+当前的)
            callHistoryMap.putAll(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS));
            //状态来到时，判断下是否需要推送到ES 进行入库
            check = checkCanOrNotPushToBatchInsertQueue(callHistoryMap,resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS),state);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("{} checkCanOrNotPushToBatchInsertQueue Failed! sessionId:{}",state.getSessionId());
            check = false;
        }
        //如果需要则将呼叫记录推送到ES 保存
        if(check){
            logger.debug("{} start pulishToBatchInsert,sessionId:{}", state.getSessionId());
            todoSaveCallRcord(callHistoryMap);
            //这里需要做个特殊，将记录推送到爱家
            if(callHistoryMap.get(RedisFields.CALL_HISTORY_COMMIT_TO)!=null&&"11".equals(callHistoryMap.get(RedisFields.CALL_HISTORY_COMMIT_TO).toString())){
                logger.info(">>>>>>>>>>>>>开始推送爱家数据-------commitTo:{}",callHistoryMap.get(RedisFields.CALL_HISTORY_COMMIT_TO));
                pushRecordToBL(callHistoryMap);
            }
        }
        //流程结束

    }

    /**
     * 读redis
     * */
    protected abstract Map<String,String> readRedis(String sessionId);

    /**
     * 处理读redis失败
     * */
    protected abstract String handleReadRedisFailed(T Data);

    /**
     * 写redis
     * */
    protected abstract String writeRedis(String sessionId,Map<String,String> map);

    /**
     * 处理写redis失败
     * */
    protected abstract String handleWriteRedisFailed(String sessionId,Map<String,String> map);

    /**
     * 检测数据是否满足入库
     * 统一检测DISCONNECT,如果正常通话，延迟到录音文件返回再入库
     * */
    protected abstract boolean checkCanOrNotPushToBatchInsertQueue(Map<String,String> callHistoryMap, Map<String,String> redisMap,T data);

    /**
     *处理websocket推送失败
     * */
    protected abstract void handlePushStateToClientFail();



    /**
     * 分析呼叫状态:
     *更新callHistory状态
     *
     *如果返回值中包含key是invalid，应该当不处理
     * @return json
     * */
    protected abstract Map<String, Map<String,String>> analyzeCallState(T callState,Map<String,String> callHistoryMap) throws Exception;

    protected abstract void todoSaveCallRcord(Map<String,String> callHistoryMap);


    /**
     * 推送状态到客户端
     * */
    protected abstract void pushStateToClient(Map<String,String> callHistoryMap, Map<String,Map<String,String>> resultMap) throws Exception;

    /**
     * 将记录推送到保利逻辑为，入队列前先记录redis,成功推送以后，删除redis记录，反正通过每分钟的job进行重推，成功以后删redis
     * @param callHistoryMap
     * @throws Exception
     */
    protected abstract void pushRecordToBL(Map<String,String> callHistoryMap) ;


}
